/*
 *  StochasticSoundObject.h
 *  SoundController0002
 *
 *  Created by jiro on 10/07/12.
 *  Copyright 2010 jiro music. All rights reserved.
 *
 */

#pragma once

#include "../SoundController.h"
#include <vector>
#include <boost/random.hpp>
#include "tbb/tick_count.h"

namespace sc
{

	///	演奏時間と密度を指定し、密度によって全てが制御されるサウンド
	///	密度は単位時間当たりの音数と周波数を決定する。
	///	波形はサイン波を使う
	template< class AudioData > 
	class StochasticSoundObject000
	{
	private:
	
		double duration;
		
		double density;

		tbb::tick_count tickCountForRandomSeed;

	public:

		StochasticSoundObject000()
			: duration( 0 ),
			  density( 0 ),
			  tickCountForRandomSeed()
		{}

		StochasticSoundObject000( double duration, double density )
			: duration( duration ),
			  density( density ),
			  tickCountForRandomSeed( tbb::tick_count::now() )
		{
			if ( density < 0.05 ) density = 0.05;
			if ( density > 20.0 ) density = 20.0;
		}
		
		void GetAudioElememts( double baseTime, std::vector< AudioElement< AudioData > >& audioElements ) const
		{
			//	---- ガウスノイズ生成機を生成
			double mean = 0;
			double sigma = 1.0 / ( 8.0 * density );
			boost::mt19937 engine( static_cast<unsigned>( 1000000 * ( tbb::tick_count::now() - tickCountForRandomSeed ).seconds() ) );
//			boost::mt19937 engine( static_cast<unsigned> ( std::time( 0 ) ) );
			boost::normal_distribution<> distributon( mean, sigma );
			boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > noise_generator( engine, distributon );
			//	----

			//	---- 音の発生時刻を求める
			std::vector< double > soundOccurTimes;
			for ( int count = 0; count < duration / ( 1.0 / density ); count++ )
			{
				double time = count * ( 1.0 / density );
				double noise = noise_generator();
				if ( time + noise >= 0 )
				{
					time += noise;
				}
				soundOccurTimes.push_back( time );
			}
			//	----
			
			//	---- 周波数用のノイズ生成機を生成
			sigma = 20;
			distributon = boost::normal_distribution<>( mean, sigma );
			boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > noise_generator2( engine, distributon );
			//	----

			//	---- 各音の周波数を計算
			const Line* frequencyLine = & LineFactory::Create( Line::Type_Straight, 0.05, 40, 20, 10000 );
			std::vector< AudioData > frequencies;
			for ( size_t i = 0; i < soundOccurTimes.size(); i++ ) 
			{
				frequencies.push_back( frequencyLine->GetY( density ) + noise_generator2() );
			}
			//	----

			//	---- SoundElment を生成
			double attackRate = 0.1;
			double decayRate = 0.1;
			double sustainRate = 0.5;
			double releaseRate = 0.3;
			double attackMaxDynamics = 0.8;
			double sustainDynamics = 0.6;
			std::vector< const SoundElement< AudioData >* > soundElements;
			for ( size_t i = 0; i < soundOccurTimes.size(); i++ ) 
			{
				double length;
				if ( i + 1 != soundOccurTimes.size() )
				{
					length = soundOccurTimes[ i + 1 ] - soundOccurTimes[ i ];
				}
				else
				{
					length = duration - soundOccurTimes[ i ];
				}
				
				double attackEndTime = length * attackRate;
				double decayEndTime = attackEndTime + length * decayRate;
				double sustainEndTime = decayEndTime + length * sustainRate;
				double releaseEndTime = sustainEndTime + length * releaseRate;

				const SoundElement< AudioData >* element = 
					SoundElementFactory< AudioData >::Create(
						attackEndTime, & LineFactory::Create( Line::Type_Straight, 0, 0, attackEndTime, attackMaxDynamics ),
						decayEndTime, & LineFactory::Create( Line::Type_Straight, attackEndTime, attackMaxDynamics, decayEndTime, sustainDynamics ),
						sustainEndTime, & LineFactory::Create( Line::Type_Straight, decayEndTime, sustainDynamics, sustainEndTime, sustainDynamics ),
						releaseEndTime, & LineFactory::Create( Line::Type_Straight, sustainEndTime, sustainDynamics, releaseEndTime, 0 ),
						WaveTableFactory::Create( WaveTable::Type_Sine, frequencies[ i ] ) );
				soundElements.push_back( element );
			}
			//	----

			//	---- AudioElement を生成
			for ( size_t i = 0; i < soundOccurTimes.size(); i++ )
			{
				AudioElement< AudioData > element( baseTime + soundOccurTimes[ i ], soundElements[ i ] );
				audioElements.push_back( element );
			}
			//	----
		}
	};
	
	typedef StochasticSoundObject000< AudioData32 > StochasticSoundObject000_32;
	
	typedef StochasticSoundObject000< AudioData64 > StochasticSoundObject000_64;
}
